winsafe\kernel\handles/hfile.rs
1#![allow(non_camel_case_types, non_snake_case)]
2
3use crate::co;
4use crate::decl::*;
5use crate::guard::*;
6use crate::kernel::{ffi, privs::*};
7use crate::prelude::*;
8
9handle! { HFILE;
10 /// Handle to a
11 /// [file](https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types#hfile).
12 /// Originally just a `HANDLE`.
13 ///
14 /// Unless you need something specific, consider using the
15 /// [`File`](crate::File) high-level abstraction.
16}
17
18impl HFILE {
19 /// [`CreateFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew)
20 /// function.
21 ///
22 /// The error code is also returned because it can carry information even if
23 /// the file is successfully open.
24 ///
25 /// Unless you need something specific, consider using the
26 /// [`File`](crate::File) high-level abstraction.
27 ///
28 /// # Examples
29 ///
30 /// Opening an existing file as read-only:
31 ///
32 /// ```no_run
33 /// use winsafe::{self as w, prelude::*, co};
34 ///
35 /// let (hfile, status) = w::HFILE::CreateFile(
36 /// "C:\\Temp\\test.txt",
37 /// co::GENERIC::READ,
38 /// Some(co::FILE_SHARE::READ),
39 /// None,
40 /// co::DISPOSITION::OPEN_EXISTING,
41 /// co::FILE_ATTRIBUTE::NORMAL,
42 /// None,
43 /// None,
44 /// None,
45 /// )?;
46 /// # w::SysResult::Ok(())
47 /// ```
48 ///
49 /// Opening a file for read and write. If the file doesn't exist, create it:
50 ///
51 /// ```no_run
52 /// use winsafe::{self as w, prelude::*, co};
53 ///
54 /// let (hfile, status) = w::HFILE::CreateFile(
55 /// "C:\\Temp\\test.txt",
56 /// co::GENERIC::READ | co::GENERIC::WRITE,
57 /// None,
58 /// None,
59 /// co::DISPOSITION::OPEN_ALWAYS,
60 /// co::FILE_ATTRIBUTE::NORMAL,
61 /// None,
62 /// None,
63 /// None,
64 /// )?;
65 /// # w::SysResult::Ok(())
66 /// ```
67 #[must_use]
68 pub fn CreateFile(
69 file_name: &str,
70 desired_access: co::GENERIC,
71 share_mode: Option<co::FILE_SHARE>,
72 security_attributes: Option<&SECURITY_ATTRIBUTES>,
73 creation_disposition: co::DISPOSITION,
74 attributes: co::FILE_ATTRIBUTE,
75 flags: Option<co::FILE_FLAG>,
76 security: Option<co::FILE_SECURITY>,
77 hfile_template: Option<&HFILE>,
78 ) -> SysResult<(CloseHandleGuard<HFILE>, co::ERROR)> {
79 unsafe {
80 match HFILE(ffi::CreateFileW(
81 WString::from_str(file_name).as_ptr(),
82 desired_access.raw(),
83 share_mode.unwrap_or_default().raw(),
84 pcvoid_or_null(security_attributes),
85 creation_disposition.raw(),
86 attributes.raw()
87 | flags.unwrap_or_default().raw()
88 | security.map_or(0, |s| SECURITY_SQOS_PRESENT | s.raw()),
89 hfile_template.map_or(std::ptr::null_mut(), |h| h.ptr()),
90 ) as _)
91 {
92 HFILE::NULL | HFILE::INVALID => Err(GetLastError()),
93 handle => Ok((CloseHandleGuard::new(handle), GetLastError())),
94 }
95 }
96 }
97
98 /// [`CreateFileMapping`](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw)
99 /// function.
100 ///
101 /// Unless you need something specific, consider using the
102 /// [`FileMapped`](crate::FileMapped) high-level abstraction.
103 #[must_use]
104 pub fn CreateFileMapping(
105 &self,
106 mapping_attrs: Option<&SECURITY_ATTRIBUTES>,
107 protect: co::PAGE,
108 sec: Option<co::SEC>,
109 max_size: Option<u64>,
110 mapping_name: Option<&str>,
111 ) -> SysResult<CloseHandleGuard<HFILEMAP>> {
112 unsafe {
113 ptr_to_sysresult_handle(ffi::CreateFileMappingFromApp(
114 self.ptr(),
115 pcvoid_or_null(mapping_attrs),
116 protect.raw() | sec.map_or(0, |f| f.raw()),
117 max_size.unwrap_or_default(),
118 WString::from_opt_str(mapping_name).as_ptr(),
119 ))
120 .map(|h| CloseHandleGuard::new(h))
121 }
122 }
123
124 /// [`GetFileInformationByHandle`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle)
125 /// function.
126 pub fn GetFileInformationByHandle(&self) -> SysResult<BY_HANDLE_FILE_INFORMATION> {
127 let mut fi = BY_HANDLE_FILE_INFORMATION::default();
128 bool_to_sysresult(unsafe { ffi::GetFileInformationByHandle(self.ptr(), pvoid(&mut fi)) })
129 .map(|_| fi)
130 }
131
132 /// [`GetFileSizeEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex)
133 /// function.
134 #[must_use]
135 pub fn GetFileSizeEx(&self) -> SysResult<u64> {
136 let mut sz_buf = 0i64;
137 bool_to_sysresult(unsafe { ffi::GetFileSizeEx(self.ptr(), &mut sz_buf) })
138 .map(|_| sz_buf as _)
139 }
140
141 /// [`GetFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletime)
142 /// function.
143 ///
144 /// Returns, respectively:
145 /// 1. creation time;
146 /// 2. last access time;
147 /// 3. last write time.
148 ///
149 /// # Examples
150 ///
151 /// ```no_run
152 /// use winsafe::{self as w, prelude::*, co};
153 ///
154 /// let hfile: w::HFILE; // initialized somewhere
155 /// # let hfile = w::HFILE::NULL;
156 ///
157 /// let (creation, last_access, last_write) = hfile.GetFileTime()?;
158 /// # w::SysResult::Ok(())
159 /// ```
160 pub fn GetFileTime(&self) -> SysResult<(FILETIME, FILETIME, FILETIME)> {
161 let (mut creation, mut last_access, mut last_write) =
162 (FILETIME::default(), FILETIME::default(), FILETIME::default());
163
164 bool_to_sysresult(unsafe {
165 ffi::GetFileTime(
166 self.ptr(),
167 pvoid(&mut creation),
168 pvoid(&mut last_access),
169 pvoid(&mut last_write),
170 )
171 })
172 .map(|_| (creation, last_access, last_write))
173 }
174
175 /// [`GetFileType`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfiletype)
176 /// function.
177 #[must_use]
178 pub fn GetFileType(&self) -> SysResult<co::FILE_TYPE> {
179 match unsafe { co::FILE_TYPE::from_raw(ffi::GetFileType(self.ptr())) } {
180 co::FILE_TYPE::UNKNOWN => match GetLastError() {
181 co::ERROR::SUCCESS => Ok(co::FILE_TYPE::UNKNOWN), // actual unknown type
182 err => Err(err),
183 },
184 ty => Ok(ty),
185 }
186 }
187
188 /// [`LockFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfile)
189 /// function.
190 ///
191 /// In the original C implementation, you must call
192 /// [`UnlockFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-unlockfile)
193 /// as a cleanup operation.
194 ///
195 /// Here, the cleanup is performed automatically, because `LockFile` returns
196 /// an [`UnlockFileGuard`](crate::guard::UnlockFileGuard), which
197 /// automatically calls `UnlockFile` when the guard goes out of scope. You
198 /// must, however, keep the guard alive, otherwise the cleanup will be
199 /// performed right away.
200 ///
201 /// # Examples
202 ///
203 /// ```no_run
204 /// use winsafe::{self as w, prelude::*};
205 ///
206 /// let hfile: w::HFILE; // initialized somewhere
207 /// # let hfile = w::HFILE::NULL;
208 ///
209 /// let total_size = hfile.GetFileSizeEx()?;
210 ///
211 /// let _lock_guard = hfile.LockFile(0, total_size as _)?; // keep guard alive
212 ///
213 /// // file read/write operations...
214 ///
215 /// // UnlockFile() called automatically
216 /// # w::SysResult::Ok(())
217 /// ```
218 #[must_use]
219 pub fn LockFile(&self, offset: u64, num_bytes_to_lock: u64) -> SysResult<UnlockFileGuard<'_>> {
220 unsafe {
221 bool_to_sysresult(ffi::LockFile(
222 self.ptr(),
223 LODWORD(offset),
224 HIDWORD(offset),
225 LODWORD(num_bytes_to_lock),
226 HIDWORD(num_bytes_to_lock),
227 ))
228 .map(|_| UnlockFileGuard::new(self, offset, num_bytes_to_lock))
229 }
230 }
231
232 /// [`ReadFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile)
233 /// function.
234 ///
235 /// Reads at most `buffer.len()` bytes from the file, starting at the
236 /// current file pointer offset. Returns how many bytes were actually read.
237 /// The file pointer is then incremented by the number of bytes read.
238 ///
239 /// Note that asynchronous reading – which use the
240 /// [`OVERLAPPED`](crate::OVERLAPPED) struct – is not currently supported by
241 /// this method, because the buffer must remain untouched until the async
242 /// operation is complete, thus making the method unsound.
243 pub fn ReadFile(&self, buffer: &mut [u8]) -> SysResult<u32> {
244 let mut bytes_read = 0u32;
245 bool_to_sysresult(unsafe {
246 ffi::ReadFile(
247 self.ptr(),
248 buffer.as_mut_ptr() as _,
249 buffer.len() as _,
250 &mut bytes_read,
251 std::ptr::null_mut(),
252 )
253 })
254 .map(|_| bytes_read)
255 }
256
257 /// [`SetEndOfFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setendoffile)
258 /// function.
259 pub fn SetEndOfFile(&self) -> SysResult<()> {
260 bool_to_sysresult(unsafe { ffi::SetEndOfFile(self.ptr()) })
261 }
262
263 /// [`SetFilePointerEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfilepointerex)
264 /// function.
265 pub fn SetFilePointerEx(
266 &self,
267 distance_to_move: i64,
268 move_method: co::FILE_STARTING_POINT,
269 ) -> SysResult<i64> {
270 let mut new_offset = 0i64;
271
272 bool_to_sysresult(unsafe {
273 ffi::SetFilePointerEx(self.ptr(), distance_to_move, &mut new_offset, move_method.raw())
274 })
275 .map(|_| new_offset)
276 }
277
278 /// [`SetFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime)
279 /// function.
280 pub fn SetFileTime(
281 &self,
282 creation_time: Option<&FILETIME>,
283 last_access_time: Option<&FILETIME>,
284 last_write_time: Option<&FILETIME>,
285 ) -> SysResult<()> {
286 bool_to_sysresult(unsafe {
287 ffi::SetFileTime(
288 self.ptr(),
289 pcvoid_or_null(creation_time),
290 pcvoid_or_null(last_access_time),
291 pcvoid_or_null(last_write_time),
292 )
293 })
294 }
295
296 /// [`WriteFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile)
297 /// function.
298 ///
299 /// Returns the number of bytes written.
300 ///
301 /// Note that asynchronous writing – which use the
302 /// [`OVERLAPPED`](crate::OVERLAPPED) struct – is not currently supported by
303 /// this method, because the buffer must remain untouched until the async
304 /// operation is complete, thus making the method unsound.
305 pub fn WriteFile(&self, data: &[u8]) -> SysResult<u32> {
306 let mut bytes_written = 0u32;
307 bool_to_sysresult(unsafe {
308 ffi::WriteFile(
309 self.ptr(),
310 vec_ptr(data) as _,
311 data.len() as _,
312 &mut bytes_written,
313 std::ptr::null_mut(),
314 )
315 })
316 .map(|_| bytes_written)
317 }
318}